package cn.gs.exchanger;

// @author gs
import cn.gs.util.monitor.TimerMonitor;
import cn.gs.util.set.Pair;
import cn.gs.util.set.TypeManager;
import java.util.Map.Entry;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ExchangerRouter {

    //UNI REG   
    private Map<String, Pair<Stack<Exchanger>, List<Exchanger>>> servers = new HashMap<String, Pair<Stack<Exchanger>, List<Exchanger>>>();

    public void removeAll(Exchanger listener) {
        Logger.getLogger(Exchanger.class.getName()).log(Level.INFO, "Remove_all_{0}", listener.remoteIP());
        for (Entry<String, Pair<Stack<Exchanger>, List<Exchanger>>> entry : servers.entrySet()) {
            if (entry.getValue() != null) {
                if (entry.getValue().getFirst() != null) {
                    entry.getValue().getFirst().remove(listener);
                }
                if (entry.getValue().getSecond() != null) {
                    entry.getValue().getSecond().remove(listener);
                }
            }
        }
    }

    private Pair<Stack<Exchanger>, List<Exchanger>> getServerByName(String name) {
        Pair<Stack<Exchanger>, List<Exchanger>> pair = servers.get(name);
        if (pair == null) {
            pair = new Pair<Stack<Exchanger>, List<Exchanger>>(new Stack<Exchanger>(), Collections.synchronizedList(new LinkedList<Exchanger>()));
            servers.put(name, pair);
        }
        return pair;
    }

    public synchronized void uni(List<String> names, Exchanger server) {
        Logger.getLogger(Exchanger.class.getName()).log(Level.INFO, "Unique_Server_{0}_{1}", new Object[]{server.remoteIP(), TypeManager.list2str(names, "_")});
        for (String name : names) {
            Pair<Stack<Exchanger>, List<Exchanger>> pair = getServerByName(name);
            pair.getFirst().push(server);
        }
    }

    public synchronized void reg(List<String> names, Exchanger server) {
        Logger.getLogger(Exchanger.class.getName()).log(Level.INFO, "Fair_Server_{0}_{1}", new Object[]{server.remoteIP(), TypeManager.list2str(names, "_")});
        for (String name : names) {
            Pair<Stack<Exchanger>, List<Exchanger>> pair = getServerByName(name);
            if (!pair.getSecond().contains(server)) {
                pair.getSecond().add(server);
            }
        }
    }

    public synchronized void del(List<String> names, Exchanger server) {
        Logger.getLogger(Exchanger.class.getName()).log(Level.INFO, "Fair_Server_{0}_{1}", new Object[]{server.remoteIP(), TypeManager.list2str(names, "_")});
        for (String name : names) {
            Pair<Stack<Exchanger>, List<Exchanger>> pair = getServerByName(name);
            if (pair != null) {
                if (pair.getFirst() != null) {
                    pair.getFirst().remove(server);
                }
                if (pair.getSecond() != null) {
                    pair.getSecond().remove(server);
                }
            }
        }
    }
    static AtomicInteger routeai = new AtomicInteger();

    public Exchanger route(ExchangerCommand cmd) {
        routeai.incrementAndGet();
        Exchanger exchg = null;
        //choose server provider
        Pair<Stack<Exchanger>, List<Exchanger>> pair = servers.get(cmd.getServer());
        if (pair == null) {
            return null;
        } else if (!pair.getFirst().isEmpty()) {
            exchg = pair.getFirst().peek();
            Logger.getLogger(Exchanger.class.getName()).log(Level.FINE, "Route_Unique_{0}->{1}", new Object[]{cmd.toString(), exchg.remoteIP()});
            return exchg;
        } else if (!pair.getSecond().isEmpty()) {
            int index = (new Random()).nextInt(pair.getSecond().size());
            exchg = pair.getSecond().get(index);
            Logger.getLogger(Exchanger.class.getName()).log(Level.FINE, "Route_{0}->{1}", new Object[]{cmd.toString(), exchg.remoteIP()});
            return exchg;
        } else {
            return null;
        }
    }

    public List<String> allService(List<String> args) {
        return new LinkedList<String>(servers.keySet());
    }

    public synchronized List<String> serviceProviderCount(List<String> args) {
        List<String> ls = new LinkedList<String>();
        for (String a : args) {
            Pair<Stack<Exchanger>, List<Exchanger>> p = servers.get(a);
            if (p == null) {
                ls.add("0");
            } else {
                if (p.getFirst().isEmpty() && p.getSecond().isEmpty()) {
                    servers.remove(a);
                }
                ls.add(String.valueOf(p.getFirst().size() + p.getSecond().size()));
            }
        }
        return ls;
    }
}
